home *** CD-ROM | disk | FTP | other *** search
/ PC-Blue - MS DOS Public Domain Library / PC-Blue MS-DOS Public Domain Library - NYACC.iso / vol309 / jdutil.arc / CP.ASM < prev    next >
Encoding:
Assembly Source File  |  1986-08-14  |  36.9 KB  |  886 lines

  1.         TITLE CP - MSDOS FILE COPY UTILITY
  2.         PAGE 55,132
  3. ;***************************************************************************
  4. ;       THIS PROGRAM COPIES ONE OR MORE FILES, OR THE CONTENTS OF A WHOLE
  5. ;       DIRECTORY, TO ANOTHER DISK, FILE OR DIRECTORY.
  6. ;
  7. ;       USAGE (afn = ambiguous file name, ufn = unambiguous file name,
  8. ;              dir = directory):
  9. ;
  10. ;               CP ufn1 ufn2    - copies ufn1 to unf2
  11. ;
  12. ;               CP afn1 afn2 ... dir  - copies one or more files into dir.
  13. ;
  14. ;               CP -R dir1 dir2  - if dir2 doesn't exist, creates it and
  15. ;                                 copies dir1 to dir2.
  16. ;
  17. ;                               - if dir2 exists, creates dir2\dir1 and
  18. ;                                 copies dir1 to it.
  19. ;
  20. ;       SWITCHES (OPTIONAL):
  21. ;
  22. ;        CP -I  prompt before overwriting file
  23. ;
  24. ;        CP -R  allow recursive copying of directories.
  25. ;
  26. ;               CP -V  turns on "verbose" mode (shows name of each file as it
  27. ;                      is copied).
  28. ;***************************************************************************
  29. ;   TO BUILD CP.EXE:
  30. ;    MASM CP,CP,NUL,NUL
  31. ;    LINK CP,CP,NUL,ASM -C3100 -DO
  32. ;***************************************************************************
  33. ;    BY: JON DART
  34. ;        DEPARTMENT OF ANTHROPOLOGY
  35. ;        UCSD C-001
  36. ;        LA JOLLA, CA 92093
  37. ;***************************************************************************
  38. ;
  39. ;    VERSION 1.4, 06-JUL-86 (CHANGES TO MEMORY ALLOC., ALLOWS HYPHEN FOR
  40. ;                SWITCHES, NOW ASSEMBLES UNDER MASM 4.0)
  41. ;    VERSION 1.3, 30-JUN-86 (MINOR CLEANUP, ADDS I AND R SWITCHES, REMOVES
  42. ;                C SWITCH)
  43. ;       VERSION 1.2, 26-APR-86 (DOESN'T EXIT AFTER USER TYPES N TO OVERWRITE
  44. ;                    MSG)
  45. ;       VERSION 1.1, 31-MAR-86 (BUG FIXES)
  46. ;       VERSION 1.0, 30-MAR-86 (MODIFIED FROM MV v. 1.7)
  47. ;***************************************************************************
  48.  
  49. PATHSIZE EQU    65                      ;MAX. SIZE OF DOS PATHNAME, +1
  50. PRGSIZE    EQU    1800H            ;MAX. SIZE OF CODE AND FIXED DATA
  51. BUFSIZE EQU     32*1024                 ;SIZE OF COPY BUFFER
  52. MAXLEVEL EQU    12                      ;MAX NESTING LEVEL FOR DIRECTORIES
  53. MAXARGS EQU     40                      ;MAXIMUM # OF COMMAND LINE ARGUMENTS
  54. TRUE    EQU     1
  55. FALSE   EQU     0
  56. CONFIRM EQU     FALSE                   ;"CONFIRM BEFORE OVERWRITE" OPTION (DEFAULT VALUE)
  57. RECURSE EQU    FALSE            ;"RECURSIVE" DEFAULT
  58. VERBOSE EQU     FALSE                   ;"VERBOSE" OPTION (DEFAULT VALUE)
  59. M       EQU     BYTE PTR 0[BX]
  60. BIT$DIR EQU     00010000B               ;BIT IN ATTRIBUTE FOR DIRECTORY
  61. BIT$RO  EQU     00000001B               ;BIT IN ATTRIBUTE FOR WRITE-PROTECT
  62.  
  63.         .XLIST
  64.         INCLUDE ASCII.DEF
  65.         INCLUDE MSDOS2.DEF
  66.     INCLUDE MACROS.DEF
  67.         .LIST
  68.  
  69. MVINFO  STRUC
  70. NEWDIR  DW      1 DUP (?)               ;FLAG, =1 IF NEW DIRECTORY CREATED
  71. SRCTYPE DB     2 DUP (?)                ;TYPE OF SOURCE (0 IF UFN)
  72. DESTTYPE DB    2 DUP (?)                ;TYPE OF DEST (0 IF UFN)
  73. ARG1    DB      PATHSIZE DUP (?)        ;FIRST ARGUMENT (SOURCE)
  74. ARG2    DB      PATHSIZE DUP (?)        ;SECOND ARGUMENT (DEST)
  75. ARG2A   DB      PATHSIZE DUP (?)        ;SOURCE PREFIX + DEST
  76. SSPATH  DB      PATHSIZE DUP (?)        ;SOURCE SEARCH PATH
  77. SPREFIX DB      PATHSIZE DUP (?)        ;SOURCE LEAD-IN PATH
  78. DSPATH  DB      PATHSIZE DUP (?)        ;DEST SEARCH PATH
  79.                                         ;(USED ONLY AS SCRATCH AREA)
  80. DPREFIX DB      PATHSIZE DUP (?)        ;DEST LEAD-IN PATH
  81. SRCNAME DB      PATHSIZE DUP (?)        ;UNAMBIGUOUS SOURCE NAME
  82. DESTNAME DB     PATHSIZE DUP (?)        ;UNAMBIG. DEST NAME
  83. DTA     DB      128 DUP (?)             ;DTA FOR SEARCH FN.
  84. MVINFO  ENDS
  85. MVSTRUCSIZE EQU 9*PATHSIZE+135          ;SIZE OF STRUCTURE
  86.  
  87. DGROUP  GROUP DATA,STACK
  88. DATA    SEGMENT WORD PUBLIC
  89. ;       GLOBAL MEMORY DEFINITIONS:
  90. ;
  91. MSG1    DB 'CP Version 1.4 by Jon Dart (06-Jul-86)',CR,LF,CR,LF
  92.         DB 'USAGE (afn = ambiguous file name, ufn = unambiguous file name,'
  93.         DB CR,LF
  94.         DB '       dir = directory):',CR,LF,CR,LF
  95.         DB 'CP ufn1 ufn2          copies ufn1 to ufn2.',CR,LF,CR,LF
  96.         DB 'CP afn1 afn2 ... dir  copies one or more files into dir.',CR,LF
  97.         DB CR,LF
  98.         DB "CP -R dir1 dir2       if dir2 doesn't exist, creates it and copies"
  99.         DB CR,LF
  100.         DB '                      all files from dir1 to dir2.',CR,LF,CR,LF
  101.         DB "                      if dir2 exists, creates dir2\dir1 and copies"
  102.         DB CR,LF
  103.         DB '                      all files from dir1 into it.',CR,LF,CR,LF
  104.         DB 'SWITCHES (OPTIONAL):',CR,LF,CR,LF
  105.     DB '-I   prompt before overwriting files.',CR,LF,CR,LF
  106.     DB '-R   allow recursive copying of directories.',CR,LF,CR,LF
  107.         DB '-V   echo file names as they are copied.',CR,LF
  108.         DB 0
  109. MSG2    DB      ': file not found.',CR,LF,0
  110. MSG3    DB      'Source and dest are incompatible.',CR,LF,0
  111. MSG4    DB      ' exists. Overwrite [Y or N]? ',0
  112. MSG5    DB      ': open failed.',CR,LF,0
  113. MSG6    DB      ': file is R/O. Are you SURE [Y or N]? ',0
  114. MSG7    DB    ': directory.',CR,LF,0
  115. MSG8    DB      ': write error.',CR,LF,0
  116. MSG9    DB      ': read error.',CR,LF,0
  117. MSG10   DB      ': write error (probably disk full).',CR,LF,0
  118. MSG11   DB      ': rename failed.',CR,LF,0
  119. MSG12   DB      ": can't create.",CR,LF,0
  120. MSG13   DB      ": can't remove.",CR,LF,0
  121. MSG14   DB      "Directories nested too deep.",CR,LF,0
  122. MSG15   DB      "Insufficient memory for buffers.",CR,LF,0
  123. MSG16   DB      ": Illegal switch.",CR,LF,0
  124. MSG17   DB      "Error: source and dest are identical.",CR,LF,0
  125. MSG18   DB      "Too many arguments.",CR,LF,0
  126. DATA    ENDS
  127.  
  128. STACK   SEGMENT PARA STACK
  129.         DB      512 DUP (?)
  130. STACK   ENDS
  131.  
  132. ;       VARIABLES AND BUFFER AREAS, STORED IN FREE MEMORY ABOVE PROGRAM,
  133. ;       RELATIVE TO "BASE" (DS AND ES WILL NORMALLY POINT TO START OF THIS AREA):
  134.  
  135. RBASE   EQU     2                       ;POINTER TO MVSTRUC IN RSTACK
  136. LEVEL   EQU     4                       ;RECURSION LEVEL
  137. SRCDRIVE  EQU   6                       ;SOURCE DRIVE (0 = DEFAULT)
  138. DESTDRIVE  EQU  8                       ;DEST DRIVE (0 = DEFAULT)
  139. INHANDLE EQU    10                      ;INPUT FILE HANDLE
  140. OUTHANDLE EQU   12                      ;OUTPUT FILE HANDLE
  141. IFLAG   EQU     14                      ;CONFIRM FLAG
  142. RFLAG    EQU    16            ;RECURSIVE FLAG
  143. VFLAG   EQU     18                      ;VERBOSE FLAG
  144. CMDTAIL EQU     20                      ;STORAGE FOR COMMAND TAIL
  145. DEST_DTA EQU    CMDTAIL+128             ;HOLDS INFO ON DEST, RETURNED FROM DOS
  146.                                         ;FN 4E.
  147. NUMARGS EQU     DEST_DTA+128            ;NUMBER OF ARGUMENTS ON COMMAND LINE
  148. ARGPTRS EQU     NUMARGS+2               ;POINTERS TO START OF ARGUMENTS
  149. BUFFER  EQU     ARGPTRS+(2*MAXARGS)     ;FILE XFER BUFFER
  150. RSTACK  EQU     BUFFER+BUFSIZE          ;RECURSION STACK
  151. DATASIZE EQU    (RSTACK)+(MAXLEVEL*MVSTRUCSIZE)+256
  152.  
  153.         PAGE +
  154. CODE    SEGMENT BYTE PUBLIC
  155. ASSUME CS:CODE,DS:DGROUP,ES:DGROUP,SS:STACK
  156. EXTRN   CPYCNT:NEAR,UC:NEAR,UCSTR:NEAR,CRLF:NEAR
  157. EXTRN   ERRORMSG:NEAR,COUT:NEAR,CIN:NEAR,CLRCO:NEAR
  158. EXTRN   SKIPSP:NEAR,TYPTX:NEAR,ERRORMSG:NEAR,CLRCO:NEAR
  159. EXTRN   FIXPATH:NEAR,TYPE_DIR:ABS,TYPE_AFN:ABS
  160. EXTRN   TYPE_UFN:ABS,TYPE_DSP:ABS,TYPE_DRV:ABS,TYPE_UNK:ABS
  161. EXTRN   GETYORN:NEAR,UNLINK2:NEAR
  162.  
  163. ADDR    MACRO   REG,OFFST               ;COMPUTE ADDRESS OFFSET FROM BASE REGISTER (BX)
  164.         MOV     REG,BX
  165.         ADD     REG,OFFSET OFFST
  166.         ENDM
  167.  
  168. ERROR   MACRO   ERRNUM                  ;SHOW ERROR MESSAGE
  169.         MOV     DX,OFFSET DGROUP:MSG&ERRNUM
  170.     CALL    PRTERR
  171.     ENDM
  172.  
  173. ;**********************
  174. ; PROGRAM ENTRY POINT *
  175. ;**********************
  176. ENTRY:
  177.         TEST_DOS2                       ;TEST FOR DOS 2.0, EXIT IF DOS 1
  178.     MOV    AX,DS
  179.     MOV    ES,AX
  180.     MOV    BX,((PRGSIZE+DATASIZE) SHR 4)+1 ;RESERVE SPACE FOR PROGRAM+BUFFERS
  181.     MOV    AH,SET_BLOCK
  182.     INT    DOS
  183.     JB    MEMERR            ;IF ERROR
  184.     MOV    AX,DS            ;GET DATA SEG
  185.     ADD    AX,PRGSIZE SHR 4    ;ADD OFFSET TO BUFFER AREA
  186.     MOV    ES,AX            ;SET EXTRA SEG TO POINT TO BUFFERS
  187.     JMP    SHORT MEMOK
  188. MEMERR: ERROR   15
  189.         JMP     EXIT2
  190. MEMOK:
  191.         MOV     BX,OFFSET (80H)          ;POINT TO BYTE COUNT FOR COMMAND LINE
  192.         CMP     [BX],BYTE PTR 0
  193.         JE      USEMSG                  ;IF NO COMMAND TAIL
  194.         PUSH    BX
  195.         MOV     DL,[BX]
  196.         MOV     DH,0
  197.         ADD     BX,DX
  198.         INC     BX
  199.         MOV     [BX],BYTE PTR 0         ;PUT 0 BYTE AT END OF COMMAND LINE
  200.         POP     BX
  201.         INC     BX
  202.         CALL    SKIPSP                  ;SKIP LEADING SPACES
  203.         JNC     L_2                     ;IF SOMETHING ON LINE
  204. USEMSG: ERROR   1
  205.         JMP     EXIT2
  206. L_2:
  207.         MOV     SI,BX
  208.         MOV     DI,OFFSET CMDTAIL
  209.         MOV     CX,128
  210.         CALL    CPYCNT                  ;SAVE COMMAND TAIL
  211.         MOV     AX,ES
  212.         MOV     DS,AX                   ;SET DATA SEG TO VARIABLE AREA
  213.         MOV     BYTE PTR DS:IFLAG,CONFIRM  ;SET CONFIRM FLAG DEFAULT
  214.         MOV     BYTE PTR DS:VFLAG,VERBOSE  ;SET VERBOSE FLAG DEFAULT
  215.     MOV    BYTE PTR DS:RFLAG,RECURSE  ;SET RECURSIVE FLAG DEFAULT
  216.     MOV    WORD PTR DS:LEVEL,0    ;ZERO RECURSION LEVEL
  217.         MOV     BYTE PTR DS:SRCDRIVE,0  ;SET SOURCE DRIVE DEFAULT
  218.         MOV     BYTE PTR DS:DESTDRIVE,0 ;SET DEST DRIVE DEFAULT
  219. ;***************************
  220. ; COLLECT SWITCHES, IF ANY *
  221. ;***************************
  222.         MOV     BX,OFFSET CMDTAIL       ;POINT TO COMMAND TAIL
  223.         CALL    UCSTR                   ;MAKE UPPER-CASE
  224. NEXTSW:
  225.         CALL    SKIPSP
  226.         JB      USEMSG                  ;IF NOTHING ON LINE BESIDES SWITCHES
  227.         CMP     BYTE PTR [BX],'/'       ;SWITCH SPECIFIED?
  228.         JE      GOTSW            ;YES.
  229.     CMP    BYTE PTR [BX],'-'    ;CHECK FOR HYPHEN, TOO
  230.     JNE    NOSWITCH
  231. GOTSW:
  232.         INC     BX                      ;SKIP OVER SWITCH CHARACTER
  233.         CALL    SKIPSP                  ;SKIP LEADING BLANKS
  234.         JB      USEMSG                  ;IF NOTHING
  235.         CALL    UC                      ;MAKE SWITCH UPPER CASE
  236.         CMP     AL,'V'                  ;VERBOSE SWITCH?
  237.         JE      VSWITCH
  238.         CMP     AL,'R'                  ;RECURSIVE SWITCH?
  239.         JE      RSWITCH
  240.     CMP    AL,'I'            ;INTERACTIVE SWITCH?
  241.     JE     ISWITCH
  242.         CALL    COUT                    ;DISPLAY BAD CHAR.
  243.         ERROR   16                      ;ILLEGAL SWITCH
  244.         JMP     EXIT2
  245. VSWITCH:
  246.         MOV     AL,1
  247.         SUB     AL,BYTE PTR DS:VFLAG
  248.         MOV     BYTE PTR DS:VFLAG,AL    ;TOGGLE VFLAG
  249.         INC     BX                      ;SKIP SWITCH LETTER
  250.         JMP     NEXTSW
  251. RSWITCH:
  252.         MOV     AL,1
  253.         SUB     AL,BYTE PTR DS:RFLAG
  254.         MOV     BYTE PTR DS:RFLAG,AL    ;TOGGLE RFLAG
  255.         INC     BX                      ;SKIP SWITCH LETTER
  256.         JMP     NEXTSW
  257. ISWITCH:
  258.         MOV     AL,1
  259.         SUB     AL,BYTE PTR DS:IFLAG
  260.         MOV     BYTE PTR DS:IFLAG,AL    ;TOGGLE IFLAG
  261.         INC     BX                      ;SKIP SWITCH LETTER
  262.         JMP     NEXTSW
  263. ;************************************************************
  264. ; SCAN THE COMMAND LINE AND STORE POINTERS TO ALL ARGUMENTS *
  265. ;************************************************************
  266. NOSWITCH:
  267.         MOV     CX,0                    ;CX COUNTS # OF ARGUMENTS
  268.         MOV     SI,OFFSET DS:ARGPTRS    ;POINT TO ARG POINTER TABLE
  269. SAVEARG:
  270.         INC     CX                      ;BUMP ARGUMENT COUNT
  271.         CMP     CX,MAXARGS
  272.         JG      TOOMANY                 ;IF TOO MANY
  273.         MOV     DS:[SI],BX              ;SAVE POINTER TO ARG
  274.         ADD     SI,2                    ;ADVANCE TO NEXT TABLE ENTRY
  275. CNTARGS:
  276.         MOV     AL,DS:[BX]              ;GET CHAR. FROM COMMAND LINE
  277.         CMP     AL,0
  278.         JE      ENDLINE                 ;IF END OF LINE
  279.         COMPLIST <SPACE,TAB>,NEXTARG    ;SEE IF SPACE OR TAB
  280.         INC     BX
  281.         JMP     CNTARGS                 ;LOOP TILL DELIMITER FOUND
  282. NEXTARG:
  283.         CALL    SKIPSP                  ;SKIP SPACES AND TABS
  284.         JNB     SAVEARG                 ;IF NOT EOL, BACK TO TOP OF LOOP
  285. ENDLINE:
  286.         CMP     CX,0                    ;CHECK ARGUMENT COUNT
  287.         JE      NOARGS                  ;IF NO ARGS
  288.         CMP     CX,1
  289.         JG      ARGSOK                  ;IF >=2 ARGS
  290.         MOV     DS:[SI],BX              ;EXACTLY ONE ARGUMENT, SO
  291.         INC     CX                      ;MAKE A DUMMY (NULL) 2ND ARGUMENT
  292.         JMP     SHORT ARGSOK
  293. NOARGS:
  294.         JMP     USEMSG                  ;GIVE USE MESSAGE
  295. TOOMANY:
  296.         ERROR   18                      ;TOO MANY ARGUMENTS (PRETTY UNLIKELY)
  297.         JMP     EXIT2
  298. ;************************************
  299. ;* COLLECT THE DESTINATION PATHNAME *
  300. ;************************************
  301. ARGSOK: MOV     WORD PTR DS:NUMARGS,CX  ;SAVE NUMBER OF ARGUMENTS
  302.         DEC     CX                      ;NUMBER OF ARGS - 1
  303.         ADD     CX,CX                   ;TIMES TWO
  304.         MOV     SI,OFFSET DS:ARGPTRS
  305.         ADD     SI,CX                   ;POINT TO ADDR. OF LAST ARGUMENT (DEST)
  306.         MOV     BX,DS:[SI]              ;PUT ADDR. INTO BX
  307.         MOV     DI,OFFSET RSTACK+ARG2   ;POINT TO STORAGE FOR DEST
  308.         MOV     AL,[BX+1]
  309.         CMP     AL,':'                  ;CHECK FOR DEST DRIVE SPEC
  310.         JNE     GETLAST                 ;IF NONE
  311.         MOV     AL,[BX]                 ;DRIVE SPECIFIED, GET DRIVE LETTER
  312.         SUB     AL,'A'-1                ;MAKE BINARY
  313.         MOV     BYTE PTR DS:DESTDRIVE,AL   ;SAVE DRIVE
  314. GETLAST: MOV    AL,[BX]                 ;GET A CHAR. FROM CMD LINE
  315.         COMPLIST <0,SPACE,TAB>,ENDARG2  ;IF DELIMITER
  316.         STOSB                           ;NOT DELIMITER, STORE IT
  317.         INC     BX                      ;BUMP POINTER
  318.         JMP     GETLAST                 ;LOOP
  319. ENDARG2:
  320.         MOV     AL,0
  321.         STOSB                           ;END DEST W. 0
  322. ;************************************************************
  323. ;* LOOP, TAKING ONE SOURCE AT A TIME AND COPYING IT TO DEST *
  324. ;************************************************************
  325.         MOV     CX,WORD PTR DS:NUMARGS  ;GET NUMBER OF ARGS AGAIN
  326.         DEC     CX                      ;-1
  327.         MOV     SI,OFFSET DS:ARGPTRS    ;POINT TO POINTER TABLE
  328. COPY1ARG:
  329.         MOV     BX,DS:[SI]              ;GET POINTER TO ARG
  330.         PUSH    SI
  331.         PUSH    CX
  332.         CALL    COPYARG                 ;COPY IT
  333.         POP     CX
  334.         POP     SI
  335.         ADD     SI,2                    ;ADVANCE TO NEXT ARG POINTER
  336.         LOOP    COPY1ARG                ;LOOP TILL NO MORE ARGS TO COPY
  337.         JMP     EXIT2
  338.  
  339. ;**********************************
  340. ;* COPY 1 SOURCE ARGUMENT TO DEST *
  341. ;**********************************
  342. COPYARG PROC   NEAR
  343.         MOV     BYTE PTR DS:SRCDRIVE,0  ;SET SOURCE DRIVE DEFAULT
  344.         MOV     DI,OFFSET RSTACK+ARG1   ;COLLECT SOURCE
  345.         MOV     AL,[BX+1]
  346.         CMP     AL,':'                  ;CHECK FOR SOURCE DRIVE SPEC
  347.         JNE     GETARG
  348.         MOV     AL,[BX]                 ;GET DRIVE LETTER
  349.         SUB     AL,'A'-1                ;MAKE BINARY
  350.         MOV     BYTE PTR DS:SRCDRIVE,AL ;SAVE SOURCE DRIVE
  351. GETARG: MOV     AL,[BX]                 ;COPY FROM [BX] TO [DI] UNTIL DELIMITER
  352.         COMPLIST <0,SPACE,TAB>,ENDARG
  353.         STOSB
  354.         INC     BX
  355.         JMP     GETARG
  356. ENDARG: MOV     AL,0
  357.         STOSB                           ;END ARG1 W. ZERO
  358.         MOV     WORD PTR DS:RBASE,RSTACK   ;SAVE OFFSET TO RSTACK
  359.         CALL    COPYIT                  ;DO THE STUFF
  360.         RET
  361. COPYARG ENDP
  362.  
  363.         PAGE +
  364. ;********************************************************************
  365. ; THIS IS THE COPY SUBROUTINE. IT ASSUMES THAT ARG1 AND ARG2 ARE
  366. ; SET UP PROPERLY IN THE RECURSION STACK AREA, AND THAT "RBASE" POINTS
  367. ; TO THE START OF THE DATA STRUCTURE FOR THIS RECURSION LEVEL.
  368. ;
  369. COPYIT  PROC    NEAR
  370.         MOV     BX,WORD PTR DS:RBASE    ;GET BASE ADDR. (POINTER TO MVINFO)
  371.         CALL    SETUP                   ;PARSE ARGUMENTS, CHECK FOR ERRORS
  372.         JNC     NOARGERR                ;IF OK
  373.         JMP     EXIT2                   ;QUIT IF ERROR
  374. ;******************************************
  375. ; SEE IF ANYTHING MATCHES THE SOURCE SPEC *
  376. ;******************************************
  377. NOARGERR:
  378.         ADDR    DX,SSPATH               ;POINT TO SEARCH PATH
  379.         MOV     CX,31H                  ;SET SEARCH ATTRIBUTES
  380.         MOV     AH,FIND_FIRST
  381.         INT     DOS                     ;SEARCH FOR 1ST MATCH
  382.         JNC     SRCOK                   ;OK IF SOMETHING FOUND
  383.         ADDR    DX,ARG1
  384.         CALL    ERRORMSG                ;ELSE SHOW ARGUMENT
  385.         ERROR   2                       ;SAY IT DOESN'T EXIST
  386.         JMP     EXIT2
  387. ;**************************************
  388. ; CREATE DEST DIRECTORY, IF NECESSARY *
  389. ;**************************************
  390. SRCOK:  CMP     WORD PTR [BX].NEWDIR,1  ;CHECK NEW DIRECTORY FLAG
  391.         JNE     GOTONE                  ;IF NOT SET
  392.         ADDR    DX,ARG2A                ;POINT TO DEST NAME
  393.         MOV     AH,MKDIR
  394.         INT     DOS                     ;CREATE NEW DIRECTORY
  395.         JNB     GOTONE                  ;IF OK
  396.         ADDR    DX,ARG2A                ;IF CAN'T CREATE,
  397.         CALL    ERRORMSG                ;SHOW DIRECTORY NAME
  398.         ERROR   12                      ;AND ERROR MSG.
  399.         JMP     EXIT2                   ;EXIT 2 DOS
  400. ;**************
  401. ; TOP OF LOOP *
  402. ;**************
  403. GOTONE:
  404.         CALL    BUILD_NAMES             ;MAKE UNAMBIG. SOURCE AND DEST NAMES
  405.         JNC     NOSKIP
  406.         JMP     NEXTFILE                ;IF SOURCE IS "." OR ".." OR = DEST
  407. NOSKIP:
  408.         CMP     BYTE PTR DS:VFLAG,TRUE  ;CHECK VERBOSE FLAG
  409.         JNE     QUIET                   ;IF QUIET MODE
  410.         ADDR    DX,SRCNAME              ;NOT QUIET, SHOW VERBIAGE
  411.         CALL    ERRORMSG
  412.         CALL    TYPTX
  413.         DB      ' -->',SPACE+200Q
  414.         ADDR    DX,DESTNAME
  415.         CALL    ERRORMSG
  416.         CALL    CRLF
  417. QUIET:
  418.         TEST    [BX].DTA+21,BIT$DIR     ;IS SOURCE A DIRECTORY?
  419.         JZ      COPYFILE                ;NO
  420.     CMP    BYTE PTR DS:RFLAG,TRUE    ;IS R FLAG SET?
  421.     JNE    NEXTFILE        ;NO, JUST SKIP OVER DIRECTORY
  422. ;***********************************************
  423. ; IF SOURCE IS A DIRECTORY, RECURSIVELY COPY IT*
  424. ;***********************************************
  425.         CMP     WORD PTR DS:LEVEL,MAXLEVEL-1 ;ARE WE AT MAX LEVEL?
  426.         JL      NOTMAX                  ;NO
  427.         ERROR   14                      ;YES, TOO DEEP
  428.         JMP     EXIT2
  429. NOTMAX:
  430.         COPYPATH SRCNAME,(ARG1+MVSTRUCSIZE)  ;COPY SOURCE DIRECTORY TO ARG1 AT NEXT LEVEL
  431.         COPYPATH DESTNAME,(ARG2+MVSTRUCSIZE) ;COPY DEST NAME TO ARG2 AT NEXT LEVEL
  432.         PUSH    BX                      ;SAVE POINTER TO BASE
  433.         INC     WORD PTR DS:LEVEL       ;INCREMENT RECURSION LEVEL
  434.         ADD     WORD PTR DS:RBASE,MVSTRUCSIZE ;ADVANCE BASE POINTER
  435.         CALL    COPYIT                  ;COPY THE DIRECTORY
  436.         POP     BX                      ;RESTORE BASE POINTER
  437.         DEC     WORD PTR DS:LEVEL       ;DECREMENT RECURSION LEVEL
  438.         SUB     WORD PTR DS:RBASE,MVSTRUCSIZE  ;RESTORE BASE TO PREVIOUS LEVEL
  439.         ADDR    DX,DTA
  440.         MOV     AH,SET_DTA
  441.         INT     DOS                     ;RESET DTA
  442.         JMP     SHORT NEXTFILE          ;DO NEXT FILE
  443. ;*******************************
  444. ; IF SOURCE IS A FILE, COPY IT *
  445. ;*******************************
  446. COPYFILE:
  447.         CALL    COPY_FILE
  448. ;*****************
  449. ; BOTTOM OF LOOP *
  450. ;*****************
  451. NEXTFILE:
  452.         MOV     AH,FIND_NEXT
  453.         INT     DOS                     ;FIND NEXT MATCH, IF ANY
  454.         JC      NOMORE                  ;IF NONE
  455.         JMP     GOTONE                  ;GOT ONE, BACK TO TOP OF LOOP
  456. ;**********************
  457. ; NO MORE FILES, DONE *
  458. ; *********************
  459. NOMORE:
  460. JUSTCLOSE:
  461.         MOV     BX,WORD PTR DS:OUTHANDLE
  462.         MOV     AH,DOS2_CLOSE
  463.         INT     DOS                     ;CLOSE OUTPUT FILE
  464.         MOV     BX,WORD PTR DS:INHANDLE
  465.         MOV     AH,DOS2_CLOSE
  466.         INT     DOS                     ;CLOSE INPUT FILE
  467.         RET                             ;ALL DONE
  468. COPYIT  ENDP
  469.  
  470.         PAGE +
  471. ;*************************************************************************
  472. ; THIS PROCEDURE PARSES ARG1 AND ARG2 AND CHECKS FOR INCOMPATIBLE TYPES
  473. ; (E.G. "MV FOOBAR *.*").  IF SUCCESSFUL, IT SETS SSPATH = SOURCE SEARCH
  474. ; PATH, SPREFIX = SOURCE PREFIX, DSPATH = DEST SEARCH PATH (NOT USED),
  475. ; DPREFIX = DEST PREFIX, SRCTYPE = SOURCE TYPE DESTTYPE = DESTINATION TYPE.
  476. ; IT ALSO SETS "NEWDIR"=1 IF THE DESTINATION DIRECTORY MUST BE CREATED.
  477. ; ALL OF THESE VARIABLES ARE IN A STRUCTURE OF TYPE 'MVINFO' IN THE RECURSION
  478. ; STACK AREA (STARTING AT THE ADDRESS IN 'RBASE').
  479. ;
  480. ; ON RETURN, THE CARRY FLAG IS SET IF AN ERROR OCCURRED.
  481. ;
  482. SETUP   PROC    NEAR
  483.         MOV     BX,WORD PTR DS:RBASE    ;GET ADDR. OF DATA STRUCTURE
  484.         MOV     WORD PTR [BX].NEWDIR,0  ;CLEAR "NEW DIRECTORY" FLAG
  485.         ADDR    DX,DTA
  486.         MOV     AH,SET_DTA
  487.         INT     DOS                     ;SET DTA
  488.         ADDR    SI,ARG1
  489.         ADDR    DI,ARG2
  490.         COMP_STRINGS                    ;COMPARE ARG1 AND ARG2
  491.         JNE     NOTIDENT                ;IF NOT IDENTICAL
  492.         ERROR   17                      ;ARG1 = ARG2, BAD NEWS
  493.         STC
  494.         RET
  495. NOTIDENT:
  496.         ADDR    CX,SSPATH
  497.         ADDR    DX,SPREFIX
  498.         PUSH    BX
  499.         ADD     BX,OFFSET ARG1
  500.         CALL    FIXPATH                 ;PARSE SOURCE PATHNAME
  501.         POP     BX
  502.         CMP     AX,TYPE_UNK
  503.         JNE     GOODPATH                ;IF APPARENTLY OK
  504.         ADDR    DX,ARG1
  505.         CALL    ERRORMSG
  506.         ERROR   2                       ;NONEXISTENT PATHNAME, COMPLAIN
  507.         STC
  508.         RET
  509. GOODPATH:
  510.         MOV     WORD PTR [BX].SRCTYPE,AX     ;SAVE TYPE OF SOURCE
  511.     CMP    AX,TYPE_DIR        ;IS IT DIRECTORY?
  512.     JNE    RSET            ;NO.
  513.     CMP    BYTE PTR DS:RFLAG,TRUE  ;YES IT IS, IS RFLAG SET?
  514.     JE    RSET            ;YES.
  515.     ADDR    DX,ARG1            ;R FLAG NOT SET,
  516.     CALL    ERRORMSG        ;SHOW NAME
  517.     ERROR    7            ;COMPLAIN ABOUT DIRECTORY
  518.     STC                ;SIGNAL ERROR
  519.     RET
  520. RSET:
  521.         ADDR    SI,ARG2
  522. PDEST:  PUSH    SI
  523. SRCBS:  MOV     AX,[SI]                 ;FIND END OF DEST
  524.         COMPLIST <0,SPACE,TAB>,GOTEND
  525.         INC     SI
  526.         JMP     SRCBS
  527. GOTEND:
  528.         DEC     SI
  529.         CMP     [SI],BYTE PTR '\'       ;DOES DEST SPEC END W. BACKSLASH?
  530.         JNE     NOBS                    ;NO, IT DOESN'T
  531.         MOV     [SI],BYTE PTR 0         ;IF SO, REMOVE IT
  532. NOBS:   COPYPATH ARG2,ARG2A             ;MAKE ARG2A = ARG2
  533.         POP     SI                      ;POINT TO START OF ARG2 AGAIN
  534.         ADDR    CX,DSPATH
  535.         ADDR    DX,DPREFIX
  536.         PUSH    BX
  537.         MOV     BX,SI
  538.         CALL    FIXPATH                 ;PARSE DEST PATHNAME
  539.         POP     BX
  540.         MOV     WORD PTR [BX].DESTTYPE,AX       ;SAVE DEST TYPE
  541.         CMP     AL,TYPE_AFN
  542.         JE      BADDEST                 ;DEST CAN'T BE AFN
  543.         CMP     AL,TYPE_UFN
  544.         JNE     NOTUFN                  ;IF DEST TYPE IS UFN,
  545.         CMP     WORD PTR DS:NUMARGS,2   ;BETTER HAVE ONLY 1 SOURCE
  546.         JG      BADDEST
  547.         CMP     WORD PTR DS:SRCTYPE,TYPE_AFN  ;AND SOURCE TYPE BETTER NOT BE AFN
  548.         JNE     NOTUFN
  549. BADDEST:
  550.         ERROR   3
  551.         STC
  552.         RET
  553. NOTUFN:
  554.         COMPLIST <TYPE_DSP,TYPE_DRV,TYPE_DIR>,DESTDSP ;IF DEST IS DIR OR DRIVE
  555.         CMP     AL,TYPE_UNK
  556.         JNE     SHORT DESTOK            ;IF DEST EXISTS
  557. DESTNX:
  558.         MOV     AX,WORD PTR [BX].SRCTYPE  ;DEST DOESN'T EXIST, SO IF
  559.         CMP     AL,TYPE_DIR             ;SOURCE TYPE IS DIRECTORY,
  560.         JNE     DESTOK
  561.         CALL    SETUP_DEST_DIR          ;MAKE DEST A DIRECTORY, TOO
  562.         JMP     SHORT DESTOK
  563. DESTDSP: MOV    AX,WORD PTR [BX].SRCTYPE  ;DEST IS DIRECTORY, DIR SPEC OR DRIVE
  564.         CMP     AL,TYPE_DIR             ;IS SOURCE A DIRECTORY? -
  565.         JNE     DESTOK                  ;- NO
  566.         CALL    SETUP_SRC_DIR           ;- YES, SOURCE IS DIRECTORY, SET IT UP
  567.         JB      ERRRET                  ;IF ERROR
  568.         MOV     AX,WORD PTR [BX].DESTTYPE
  569.         CMP     AX,TYPE_DIR             ;IS DEST A DIRECTORY? -
  570.         JNE     DESTOK                  ;- NO
  571.         CALL    SETUP_DEST_DIR          ;- YES, SET IT UP, TOO
  572. ;*******************************
  573. ; CHECK FOR INCOMPATIBLE TYPES *
  574. ;*******************************
  575. DESTOK:
  576.         MOV     CX,WORD PTR [BX].DESTTYPE    ;GET DEST TYPE
  577.         MOV     AX,WORD PTR [BX].SRCTYPE     ;GET SOURCE TYPE
  578.         CMP     AX,TYPE_DIR             ;IS SOURCE A DIRECTORY? -
  579.         JNE     TYPEOK                  ;- NO, IT ISN'T
  580.         CMP     CX,TYPE_DIR             ;- YES, SOURCE IS DIRECTORY,
  581.         JE      TYPEOK                  ;DEST BETTER BE DIRECTORY
  582.         CMP     CX,TYPE_DRV             ;OR DRIVE SPEC
  583.         JE      TYPEOK
  584.         ERROR   3                       ;ELSE INCOMPATIBLE TYPE ERROR
  585. ERRRET: STC                             ;ERROR RETURN
  586.         RET
  587. TYPEOK: CLC                             ;NORMAL RETURN
  588.         RET
  589. SETUP   ENDP
  590.  
  591. ;**********************************************
  592. ; COPY IS FROM DIR TO DIR, DIR SPEC OR DRIVE
  593. ; BUILD FULL DEST PATHNAME (IN ARG2A) AND CHECK
  594. ; ITS TYPE.  (SETS CARRY ON ERROR)
  595. ;
  596. SETUP_SRC_DIR PROC NEAR
  597.         COPYPATH ARG2,DSPATH            ;COPY DEST DIRECTORY OR DRIVE SPEC TO
  598.                                         ;DEST PATH (USE AS SCRATCH AREA)
  599.         DEC     DI                      ;BACK UP OVER NULL
  600.         MOV     AX,WORD PTR [BX].DESTTYPE
  601.         CMP     AX,TYPE_DIR             ;SEE IF DEST IS DIRECTORY
  602.         JNE     NOTDIR                  ;NOPE
  603.         MOV     BYTE PTR [DI],'\'       ;YES, ADD BACKSLASH TO DEST NAME
  604.         INC     DI
  605.         DEC     CX
  606. NOTDIR: ADDR    SI,ARG1                 ;POINT TO SOURCE DIRECTORY NAME
  607.         CMP     BYTE PTR [SI+1],':'     ;DRIVE SPECIFIED? -
  608.         JNE     NODRV                   ;- NO IT WASN'T
  609.         ADD     SI,2                    ;- YES, IT WAS, SKIP IT
  610. NODRV:
  611.         CALL    CPYCNT                  ;COPY SOURCE DIRECTORY NAME (MINUS
  612.                                         ;DRIVE SPEC) TO DEST PATH
  613.         COPYPATH DSPATH,ARG2A           ;COPY AUGMENTED DEST PATH TO ARG2A
  614.         ADDR    CX,DSPATH
  615.         ADDR    DX,DPREFIX
  616.         PUSH    BX
  617.         ADD     BX,OFFSET ARG2A
  618.         CALL    FIXPATH                 ;PARSE FULL DEST PATHNAME
  619.         POP     BX
  620.         MOV     WORD PTR [BX].DESTTYPE,AX    ;SAVE DEST TYPE
  621.         CMP     AL,TYPE_UNK
  622.         JNE     DESTXST                 ;IF DEST EXISTS
  623.         MOV     AX,WORD PTR [BX].SRCTYPE  ;DEST DOESN'T EXIST, GET SOURCE TYPE
  624.         CMP     AX,TYPE_DIR             ;IF SOURCE IS A DIRECTORY,
  625.         JNE     DESTXST
  626.         MOV     [BX].DESTTYPE,TYPE_DIR  ;MAKE DEST A DIRECTORY, TOO
  627. DESTXST:
  628.         CLC
  629.         RET
  630. SETUP_SRC_DIR ENDP
  631.  
  632. ;***************************************************************
  633. ; THIS PROCEDURE IS CALLED IF THE DESTINATION IS A NEW DIRECTORY
  634. ;
  635. SETUP_DEST_DIR PROC NEAR
  636.         ADDR    SI,DSPATH
  637.         ADDR    DI,DPREFIX
  638.         PUSH    DI
  639.         MOV     CX,PATHSIZE
  640.         CALL    CPYCNT                  ;COPY SEARCH PATH TO PREFIX
  641.         POP     DI
  642.         MOV     CX,PATHSIZE
  643.         MOV     AL,0
  644.         REPNE   SCASB                   ;FIND END OF DEST PREFIX
  645.         DEC     DI
  646.         MOV     [DI],BYTE PTR '\'       ;ADD BACKSLASH
  647.         MOV     [DI+1],BYTE PTR 0
  648.         MOV     [BX].NEWDIR,WORD PTR 1  ;SET "NEW DIRECTORY FLAG"
  649.         MOV     WORD PTR [BX].DESTTYPE,TYPE_DIR ;SET DEST TYPE = DIRECTORY
  650.         RET
  651. SETUP_DEST_DIR ENDP
  652.  
  653.         PAGE +
  654. ;****************************************************************************
  655. ; THIS ROUTINE TAKES THE INFO ON A FILE IN THE DTA AND USES IT TO GENERATE
  656. ; FULL, UNAMBIGUOUS SOURCE AND DESTINATION FILE NAMES BY ADDING THE NECESSARY
  657. ; DIRECTORY PREFIXES TO IT.  IT SETS THE CARRY FLAG IF THE "FILE"
  658. ; IS "." OR "..", OR IF THE SOURCE IS IDENTICAL TO THE DESTINATION.
  659. ;
  660. BUILD_NAMES  PROC  NEAR
  661.         COPYPATH SPREFIX,SRCNAME        ;GET SOURCE PREFIX, COPY TO SOURCE NAME
  662.         DEC     DI                      ;BACK UP OVER NULL
  663.         ADDR    SI,(DTA+30)             ;POINT TO FILE NAME WE FOUND
  664.         CMP     [SI],BYTE PTR '.'       ;DOES IT START WITH .? -
  665.         JNE     NOTDOT                  ;- NO
  666.         STC                             ;- YES, SET CARRY TO SKIP IT
  667.         RET
  668. NOTDOT:
  669.         CALL    CPYCNT                  ;ADD IT TO SOURCE PREFIX
  670.         CMP     WORD PTR [BX].DESTTYPE,TYPE_UFN  ;IS DEST A UFN?
  671.         JE      DESTUFN                 ;YES, JUST USE IT
  672.         CMP     WORD PTR [BX].DESTTYPE,TYPE_UNK
  673.         JE      DESTUFN                 ;DITTO IF DEST DOESN'T EXIST
  674.                                         ;IF NOT, MAKE DEST NAME = SOURCE NAME
  675.         COPYPATH DPREFIX,DESTNAME       ;COPY DEST PREFIX TO DEST NAME
  676.         DEC     DI                      ;BACK UP OVER NULL
  677.         ADDR    SI,DTA+30               ;POINT TO FILE NAME WE FOUND
  678.         CALL    CPYCNT                  ;ADD IT TO DEST PREFIX
  679.         JMP     SHORT DONE              ;GO TO NEXT STEP
  680. DESTUFN:                                ;DEST IS A FILE, NOT A DIRECTORY
  681.         COPYPATH ARG2,DESTNAME          ;SO DESTNAME JUST = ARG2
  682. DONE:
  683.         CALL    CHECK_NAMES             ;CHECK SOURCE AND DEST FOR IDENTITY
  684.         RET
  685. BUILD_NAMES ENDP
  686.  
  687.         PAGE +
  688. ;*********************************************************************
  689. ; THIS PROCEDURE CHECKS THE SOURCE AND DEST FILES, AND SETS THE CARRY
  690. ; FLAG IF THEY ARE IDENTICAL
  691. ;
  692. CHECK_NAMES PROC NEAR
  693.         MOV     BX,WORD PTR DS:RBASE    ;GET ADDR. OF DATA STRUCTURE
  694.         MOV     AH,SET_DTA
  695.         MOV     DX,OFFSET DEST_DTA
  696.         INT     DOS                     ;SET DTA
  697.         ADDR    DX,ARG2                 ;POINT TO DESTINATION
  698.         MOV     CX,0FFH
  699.         MOV     AH,FIND_FIRST
  700.         INT     DOS                     ;SEARCH FOR IT
  701.         PUSHF
  702.         ADDR    DX,DTA
  703.         MOV     AH,SET_DTA
  704.         INT     DOS                     ;RESET DTA
  705.         POPF
  706.         JNB     GOTDEST                 ;IF FOUND IT
  707.         CLC                             ;OK IF IT DOESN'T EXIST
  708.         RET
  709. GOTDEST: ADDR   SI,DTA+21               ;POINT TO INFO ON SOURCE
  710.         MOV     DI,OFFSET DEST_DTA+21   ;POINT TO INFO ON DEST
  711.         MOV     CX,9                    ;SIZE OF FILE ATTRIBUTES
  712.         REPE    CMPSB                   ;COMPARE SOURCE AND DEST
  713.         JNE     NOTEQU                  ;IF NOT =
  714.         COMP_STRINGS                    ;COMPARE STRINGS
  715.         JNE     NOTEQU                  ;IF SOURCE AND DEST NAMES NOT EQUAL
  716.         STC                             ;FILES ARE EQUAL (NAMES AND ATTRIB.)
  717.         RET
  718. NOTEQU: CLC
  719.         RET
  720. CHECK_NAMES ENDP
  721.         PAGE +
  722. ;**************************************************************************
  723. ; THIS ROUTINE COPIES A SINGLE FILE (SRCNAME) TO ITS DESTINATION (DESTNAME)
  724. ;
  725. COPY_FILE PROC  NEAR
  726.         ADDR    DX,SRCNAME              ;DX = SOURCE FILE NAME
  727.         MOV     AL,READ_ACCESS
  728.         MOV     AH,DOS2_OPEN
  729.         INT     DOS                     ;TRY TO OPEN SOURCE FILE
  730.         JC      FAIL                    ;IF CAN'T
  731.         MOV     WORD PTR DS:INHANDLE,AX    ;SAVE FILE HANDLE
  732.         CALL    GETOK                   ;GET CONFIRMATION IF DEST EXISTS
  733.         JNC     OKGIVEN                 ;IF OK TO DELETE
  734.         MOV     BX,WORD PTR DS:INHANDLE ;IF NOT OK,
  735.         MOV     AH,DOS2_CLOSE
  736.         INT     DOS                     ;CLOSE INPUT FILE
  737.         RET                             ;QUIT W/O COPYING
  738. FAIL:   ADDR    DX,SRCNAME              ;POINT TO SOURCE FILE NAME
  739.         CALL    ERRORMSG                ;SHOW IT
  740.         ERROR   5                       ;COMPLAIN THAT CAN'T OPEN
  741.         JMP     EXIT2                   ;EXIT 2 DOS
  742. OKGIVEN: ADDR   DX,DESTNAME
  743.         MOV     CL,BYTE PTR [BX].DTA+21  ;MAKE DEST ATTRIBUTES=SOURCE ATTRIB.
  744.         MOV     CH,0
  745.         MOV     AH,DOS2_CREATE
  746.         INT     DOS                     ;CREATE DEST FILE (OR TRUNCATE OLD ONE)
  747.         JNC     CREATED                 ;IF OK
  748.         ADDR    DX,DESTNAME
  749.         CALL    ERRORMSG                ;CREATE FAILED, SHOW FILE NAME
  750.         ERROR   5                       ;COMPLAIN THAT CAN'T OPEN
  751.         JMP     CLOSE1
  752. CREATED:
  753.         MOV     WORD PTR DS:OUTHANDLE,AX   ;SAVE OUTPUT HANDLE
  754. COPYLOOP:
  755.         PUSH    BX
  756.         MOV     BX,WORD PTR DS:INHANDLE ;BX = FILE HANDLE
  757.         MOV     DX,OFFSET BUFFER        ;DX = BUFFER OFFSET
  758.         MOV     CX,BUFSIZE              ;CX = BUFFER SIZE
  759.         MOV     AH,READ                 ;USING DOS 2 CALL,
  760.         INT     DOS                     ;READ FROM SOURCE
  761.         POP     BX
  762.         JC      RDERR                   ;IF ERROR
  763.         MOV     CX,AX                   ;SAVE AMT. READ
  764.         CMP     AX,0
  765.         JE      ENDCOPY                 ;IF 0
  766.         PUSH    BX
  767.         MOV     BX,WORD PTR DS:OUTHANDLE ;BX = FILE HANDLE
  768.         MOV     DX,OFFSET BUFFER        ;DX = BUFFER OFFSET
  769.         MOV     AH,WRITE
  770.         INT     DOS                     ;WRITE BUFFER TO DEST
  771.         POP     BX
  772.         JC      WRERR                   ;IF ERROR
  773.         CMP     AX,CX                   ;WERE ALL BYTES WRITTEN?
  774.         JE      COPYLOOP                ;YES, KEEP GOING
  775.     ADDR    DX,DESTNAME        ;ERROR, POINT TO DEST NAME
  776.     CALL    ERRORMSG        ;SHOW IT
  777.         ERROR   10                      ;PROBABLY DISK FULL
  778.         JMP     SHORT SCRATCH        ;ABORT
  779. WRERR:  ADDR    DX,DESTNAME        ;POINT TO DEST NAME
  780.     CALL    ERRORMSG        ;SHOW IT
  781.     ERROR   8                       ;WRITE ERROR
  782.         JMP     SHORT SCRATCH        ;ABORT
  783. RDERR:  ADDR    DX,SRCNAME        ;POINT TO SOURCE NAME
  784.     CALL    ERRORMSG        ;SHOW IT
  785.     ERROR   9                       ;READ ERROR
  786.         JMP     SHORT SCRATCH        ;ABORT
  787. ENDCOPY: PUSH   BX                      ;NO ERRORS
  788.         MOV     BX,WORD PTR DS:INHANDLE
  789.         MOV     AH,FILE_TIMES
  790.         MOV     AL,0                    ;GET FILE DATE AND TIME FOR SOURCE
  791.         INT     DOS
  792.         MOV     BX,WORD PTR DS:OUTHANDLE   ;GET OUTPUT FILE HANDLE
  793.         MOV     AH,FILE_TIMES
  794.         MOV     AL,1
  795.         INT     DOS                     ;SET OUTPUT DATE AND TIME SAME AS INPUT
  796.         MOV     BX,WORD PTR DS:INHANDLE
  797.         MOV     AH,DOS2_CLOSE
  798.         INT     DOS                     ;CLOSE INPUT FILE
  799.         MOV     BX,WORD PTR DS:OUTHANDLE
  800.         MOV     AH,DOS2_CLOSE
  801.         INT     DOS                     ;CLOSE OUTPUT FILE
  802.         POP     BX
  803.         RET
  804. SCRATCH:
  805.     ADDR    DX,DESTNAME        ;POINT TO DEST FILE
  806.     CALL    UNLINK2            ;REMOVE IT
  807.     JMP    CLOSE1            ;CLOSE INPUT FILE AND EXIT
  808. COPY_FILE ENDP
  809.  
  810.         PAGE +
  811. ;*******************************************************************
  812. ;       THIS ROUTINE CHECKS TO SEE IF THE DEST FILE EXISTS.
  813. ;       IF IT DOES, AND IF THE CONFIRM FLAG IS SET, IT ASKS
  814. ;       FOR CONFIRMATION BEFORE DELETING THE FILE.  IF THE
  815. ;       CONFIRM FLAG IS NOT SET, IT JUST DELETES IT.
  816. ;       ON EXIT, 'C'=1 IF THE USER REPLIED 'N' TO THE CONFIRM MSG.
  817. ;
  818. GETOK   PROC    NEAR
  819.         ADDR    DX,DESTNAME
  820.         MOV     AL,0
  821.         MOV     AH,CHMOD
  822.         INT     DOS                     ;GET ATTRIBUTES FOR DEST
  823.         JNC     EXISTS                  ;IF FILE EXISTS
  824.         CLC
  825.         RET
  826. EXISTS:
  827.         CMP     BYTE PTR DS:IFLAG,TRUE  ;IS FLAG SET TO CONFIRM?
  828.         JNE     COK                     ;NO.
  829.         ADDR    DX,DESTNAME
  830.         CALL    ERRORMSG                ;SHOW DEST FILE
  831.         ERROR   4                       ;ASK FOR CONFIRMATION
  832.     CALL    GETYORN            ;GET Y OR N RESPONSE
  833.         CMP     AL,'Y'                  ;IS IT YES?
  834.         JNE     ABEXIT                  ;NO, SIGNAL CALLING ROUTINE
  835. COK:
  836. TRYAGAIN:
  837.         ADDR    DX,DESTNAME
  838.         MOV     AH,UNLINK
  839.         INT     DOS                     ;DELETE THE FILE
  840.         JNC     OKEXIT                  ;IF NO PROBLEM
  841.         CMP     AX,5                    ;WAS FILE R/O? (THIS OUGHT TO BE
  842.                                         ; THE ONLY POSSIBLE ERROR)
  843.         JNE     ABEXIT                  ;EXIT IF SOME OTHER ERROR
  844.     ADDR    DX,DESTNAME
  845.     CALL    ERRORMSG        ;SHOW DEST FILE NAME
  846.         ERROR   6                       ;R/O FILE, QUERY USER AGAIN
  847.     CALL    GETYORN            ;GET Y OR N RESPONSE
  848.         CMP     AL,'Y'                  ;TEST FOR 'Y' RESPONSE
  849.         JNE     ABEXIT                  ;ABORT IF USER SAYS 'N'
  850.         MOV     CX,0                    ;'Y' TYPED CLEAR ALL ATTRIBUTES
  851.         ADDR    DX,DESTNAME             ;POINT TO FILE NAME
  852.         MOV     AH,CHMOD
  853.         MOV     AL,1                    ;CHANGE ATTRIBUTES
  854.         INT     DOS                     ;TRY MAKING IT R/W
  855.         JMP     TRYAGAIN                ;TRY TO ERASE IT AGAIN
  856. ABEXIT: STC
  857.         RET
  858. OKEXIT: CLC
  859.         RET
  860. GETOK   ENDP
  861.  
  862. ; PRTERR = PRINT ERROR MESSAGE (DX POINTS TO OFFSET FROM DGROUP)
  863.  
  864. PRTERR:
  865.         PUSH    DS
  866.         MOV     AX,DGROUP
  867.         MOV     DS,AX
  868.         CALL    ERRORMSG
  869.         POP     DS
  870.     RET
  871.  
  872. CLOSE2:  MOV    BX,WORD PTR OUTHANDLE
  873.         MOV     AH,DOS2_CLOSE
  874.         INT     DOS                     ;CLOSE OUTPUT FILE
  875. CLOSE1:
  876.         MOV     BX,WORD PTR INHANDLE
  877.         MOV     AH,DOS2_CLOSE
  878.         INT     DOS                     ;CLOSE INPUT FILE
  879. EXIT2:
  880.         MOV     AH,EXIT
  881.         INT     DOS                     ;EXIT TO DOS
  882.  
  883. CODE    ENDS
  884.         END     ENTRY
  885.  
  886.